/***********************************************************************************************/ /**
*\n  @file       ds28e15.c
*\n  @brief      加密芯片ds28e15的加密程序
*\n  @details
*\n -----------------------------------------------------------------------------------
*\n  文件说明：
*\n			1. zynq7020通过MIO19与加密芯片通信。
*\n         2. 生产时写入密码到加密芯片ds28e15。
*\n         3. 验证时，host程序按照相同的算法SHA256计算密文，并与ds28e15生成的密文比较，
*\n			   相等则验证通过。
*\n -----------------------------------------------------------------------------------
*\n  版本:   	修改人:       修改日期:    		描述:
*\n  V0.01  	lxn           2020.5.17        创建
*\n
***************************************************************************************************/

/**************************************************************************************************
* 头文件
***************************************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <string.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <errno.h>
#include <pthread.h>

#include "ds28e15.h"


#define DEBUG_ENABLE  0   ///< 调试信息开关: 1=ON, 0=OFF

#if DEBUG_ENABLE
#define PCL_NONE				 "\e[0m"
#define PCL_YELLOW				 "\e[1;33m"
#define PCL_RED 				 "\e[0;31m"

#define dbg_printf(...)   \
	do{ printf(PCL_NONE "[%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)

	
#define dbg_info(...)   \
		do{ printf(PCL_NONE "[%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)
	
#define dbg_warn(...)   \
		do{ printf(PCL_YELLOW "[warn,%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)

#define dbg_error(...)   \
	do{ printf(PCL_RED "[error,%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)

#define dbg_fatal(...)   \
	do{ printf(PCL_RED "[fatal,%s,%d,%s] ", __FILE__, __LINE__, __func__); \
		printf(__VA_ARGS__); }while(0)

#else
#define dbg_error(...)
#define dbg_fatal(...)
#define dbg_warn(...)
#define dbg_printf(...)
#endif


#if 1
#define ADDR_OFFSET_OUT   0x40   
#define ADDR_OFFSET_IN    0x60	
#define ADDR_OFFSET_DIR   0x204 
#define ADDR_OFFSET_EN    0x208 
#define BIT19   		(1<<19)
#define barrier() 	 	__asm__ __volatile__("": : :"memory")

typedef struct dev_handler_t
{
	char*				name;
	uint32_t*  			phys_address; 
	volatile uint32_t*  base_address; 
	int                 size; 
	int 				fd;
} dev_handler_t;

static dev_handler_t dev_handler =
{
	.name = "gpio_handler",
	.phys_address = (void*)0xE000A000, 
	.size = 1024 * 4, 
};

// 打开gpio句柄
static int dev_handler_open(void)
{
	dev_handler_t *this = &dev_handler;
	
	if (this->fd > 0) 
		return -1;
	
	this->fd = open("/dev/mem", O_RDWR | O_SYNC);
	if (this->fd < 0)
	{
		dbg_error("open(/dev/mem) error\n");
		return -1;
	}
	this->base_address = mmap(NULL, this->size, PROT_READ | PROT_WRITE, MAP_SHARED,
	                          this->fd, (off_t)this->phys_address);
	if (this->base_address == MAP_FAILED)
	{
		this->base_address = NULL;
		dbg_error("%s.mmap(phys_address) \n", this->name);
		return -1;
	}

	return 0;
}

// 关闭gpio句柄
static int dev_handler_close(void)
{
	dev_handler_t *this = &dev_handler;
	
	if (this->fd == 0) 
		return 0;
	
	munmap((void *)this->base_address, this->size);
	close(this->fd);
	this->fd = 0;
	
	return 0;
}
// 读寄存器
static inline uint32_t dev_register_get(int offset)
{
	dev_handler_t *this = &dev_handler;

	return ( this->base_address[offset >> 2] );
	barrier();
}
// 写寄存器
static inline void dev_register_set(int offset, unsigned int val)
{
	dev_handler_t *this = &dev_handler;
	
	this->base_address[offset >> 2] = val;
	barrier();
}
// 与寄存器
static inline void dev_register_and(int offset, unsigned int val)
{
	dev_handler_t *this = &dev_handler;
	
	this->base_address[offset >> 2] &= val;
	barrier();
}

// 或寄存器
static inline void dev_register_or(int offset, unsigned int val)
{
	dev_handler_t *this = &dev_handler;
	
	this->base_address[offset >> 2] |= val;
	barrier();
}

// 异或寄存器
static inline void dev_register_xor(int offset, unsigned int val)
{
	dev_handler_t *this = &dev_handler;
	
	this->base_address[offset >> 2] ^= val;
	barrier();
}
#endif


#define AUTHENTICATED_WRITEBLOCK_PROTECTION 0xCC
#define WRITE_MEMORY_FUNCTION 	0x55
#define READ_MEMORY_FUNCTION 	0xF0
#define WRITE_BLOCK_PROTECTION 	0xC3
#define READ_PROTECTION_COMMAND		0x80
#define WRITE_PROTECTION_COMMAND 	0x40
#define EPROM_PROTECTION_COMMAND 	0x20
#define AUTHENTICATION_COMMAND 		0x10
#define READ_STATUS_COMMAND 		0xAA
#define READ_WRITE_SCRATCHPAD_COMMAND 0x0F
#define LOAD_AND_LOCKSECRET_COMMAND 	0x33
#define COMPUTE_AND_LOCK_SECRET_COMMAND 		0x3C
#define COMPUTE_AND_READ_PAGEMAC_COMMAND 		0xA5
#define AUTHENTICATED_WRITEMEMORY_COMMAND 	0x5A
#define READ_PROTECTION 			0x80
#define WRITE_PROTECTION 			0x40
#define EMPROM_Emulation 			0x20
#define AUTHENTICATION_PROTECTION 	0x10
#define SHA_256_INITIAL_LENGTH 		8

#define SEGMENT0 0x00
#define SEGMENT1 0x01
#define PAGE0 	0x00
#define PAGE1 	0x01
#define BLOCK0 	0x00
#define BLOCK1 	0x01
#define BLOCK2 	0x10
#define BLOCK3 	0x11

#define ANONYMOUS  	1
#define OUTPUT_DATA 1
#define INPUT_DATA 	0
#define ONE_WIRE_IO 0

#define WRITE   0
#define READ    1

#define TRUE   1
#define FALSE  0

#define bool    int
#define uchar   unsigned char
#define ulong   unsigned long
#define ushort  unsigned short


static unsigned char 	CRC8 	= 0;
static unsigned short 	CRC16 	= 0;

/* SHA-256 Algorithm Definition */
static unsigned long SHA_256_Initial[8]= { 
		0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,
		0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19 };   

static unsigned long SHA_CONSTANTS[] =
	{
		0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
		0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
		0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
		0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
		0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
		0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
		0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
		0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
		0xca273ece, 0xd186b8c7, 0xeada7dd6, 0xf57d4f7f, 0x06f067aa, 0x0a637dc5, 0x113f9804, 0x1b710b35,
		0x28db77f5, 0x32caab7b, 0x3c9ebe0a, 0x431d67c4, 0x4cc5d4be, 0x597f299c, 0x5fcb6fab, 0x6c44198c };

static unsigned char dscrc_table[] =
	{
		0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
		157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
		35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
		190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
		70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
		219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
		101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
		248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
		140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
		17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
		175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
		50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
		202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
		87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
		233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
		116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 };

static short oddparity[16] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
static unsigned char SECRET[32];
static unsigned long a32, b32, c32, d32, e32, f32, g32, h32; // SHA working variables
static ulong W32[16];										  // SHA message schedule
static ulong H32[8];										  // last SHA result variables
static int reverse_endian = 1;
static int sha_debug = 0;
static unsigned long SHAVM_Hash[5]; // Hash buffer, in wrong order for Dallas MAC
static unsigned char SHAVM_Message[64];
static unsigned char RomID_Buffer[8];
static unsigned char Personality_Value[4];
static unsigned char EEPROM[32];
static unsigned char Block_Status[4];
static unsigned char Scratch_Readbuffer[32];
static unsigned char Scratch_Writebuffer[32] = {
	0x11,	0x24,	0x4d,	0x2a,	0x43,	0x29,	0x4d,	0x2a,	
	0x22,	0x25,	0x62,	0x21,	0x43,	0x39,	0x4e,	0x2b,
	0x33,	0x26,	0x4d,	0x2a,	0x43,	0x09,	0x4d,	0x5e,	
	0x44,	0x27,	0x5d,	0x20,	0x03,	0x29,	0x0d,	0x43,
};
static unsigned char Secret_256bit[32] = {
	0,	0,	0,	0,	0,	0,	0,	0,  0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,  0,	0,	0,	0,	0,	0,	0,	0,
};
static unsigned char MAC_Read_Value[32];
static unsigned char MAC_Computer_Datainput[128];
static bool Verify_outcome = (bool)0;


/**************************************************************************************************
* 私有函数声明、定义
***************************************************************************************************/
static void ComputeSHA256(unsigned char *message, short length, ushort skipconst, 
						ushort reverse, unsigned char *digest);
static void ComputeMAC256(unsigned char *MT, short length, unsigned char *MAC);
static inline void init_port()
{
	dev_register_or(ADDR_OFFSET_DIR, BIT19); 
	dev_register_or(ADDR_OFFSET_OUT, BIT19);
	dev_register_or(ADDR_OFFSET_EN, BIT19); 
}

static inline void One_Wire_IO_Direction(int dir)
{
	dir ? dev_register_or(ADDR_OFFSET_DIR, BIT19) : dev_register_and(ADDR_OFFSET_DIR, ~BIT19);
}

static inline void GPIO_ResetBits()
{
	dev_register_and(ADDR_OFFSET_OUT, ~BIT19);
}

static inline void GPIO_SetBits()
{
	dev_register_or(ADDR_OFFSET_OUT, BIT19);
}

static inline void Delay_us(register int us)
{
	register int i = 0;
	do{
		barrier();
		++ i;
		barrier();
	} while(i < (660 * us));
	barrier();
}

static  int ow_reset(void)
{
	register int ret;

	One_Wire_IO_Direction(OUTPUT_DATA);
	GPIO_ResetBits( ); 
	Delay_us(60);
	GPIO_SetBits( ); 
	One_Wire_IO_Direction(INPUT_DATA);
	Delay_us(8);		
	ret = dev_register_get(ADDR_OFFSET_IN) & BIT19;
	Delay_us(50-8);
	return (ret ? -1 : 0); 	
}

static inline uint32_t read_bit(void)
{
	register uint32_t  ret;

	One_Wire_IO_Direction(OUTPUT_DATA);
	GPIO_ResetBits( );
	One_Wire_IO_Direction(INPUT_DATA);
	Delay_us(1);  
	ret = dev_register_get(ADDR_OFFSET_IN) & BIT19;
	Delay_us(11);  
	return (ret ? 1 : 0);
}

static inline void write_bit(register int bitval)
{
	if (bitval != 0)
	{
		GPIO_ResetBits();
		Delay_us(1);
		GPIO_SetBits();
		Delay_us(12);
	}
	else
	{
		GPIO_ResetBits();
		Delay_us(8);
		GPIO_SetBits( ); 
		Delay_us(5);			
	}
}

static unsigned char read_byte(void)
{
	register int i;
	register unsigned char value = 0;
	for (i = 0; i < 8; i++)
	{
		if (read_bit())
			value |= 0x01 << i; 
	}
	return (value);
}

static  void write_byte(register int val)
{
	register int i;
	One_Wire_IO_Direction(OUTPUT_DATA);
	for (i = 0; i < 8; i++) 
	{
		(val & (1<<i)) ? write_bit(1) : write_bit(0); 
	}
}

static unsigned char dowcrc(unsigned char x)
{
	CRC8 = dscrc_table[CRC8 ^ x];
	return CRC8;
}


static unsigned short docrc16(unsigned short data)
{
	data = (data ^ (CRC16 & 0xff)) & 0xff;
	CRC16 >>= 8;

	if (oddparity[data & 0xf] ^ oddparity[data >> 4])
		CRC16 ^= 0xc001;

	data <<= 6;
	CRC16 ^= data;
	data <<= 1;
	CRC16 ^= data;

	return CRC16;
}

static int Read_RomID(unsigned char *RomID)
{
	int i;
	if ((ow_reset()) != 0)
		return 0;

	write_byte(0x33);
	Delay_us(10);
	for (i = 0; i < 8; i++)
	{
		RomID[i] = read_byte();
	}

	CRC8 = 0;
	for (i = 0; i < 8; i++)
		dowcrc( RomID[i] ); 
	if (CRC8 != 0)
		return -1;
	
	return 0;
}

static int ReadBlockStatus(unsigned char BlockNum, int PersonalityByteIndicator, unsigned char *BlockStatus)
{
	unsigned char pbuf[40], cnt = 0, i;
	if ((ow_reset()) != 0)
		return -1;
	write_byte(0xCC); 
	pbuf[cnt++] = READ_STATUS_COMMAND; 
	pbuf[cnt++] = PersonalityByteIndicator ? 0xE0 : (BlockNum & 0x03);

	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();

	CRC16 = 0;
	for (i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001)
		return -1;

	if (PersonalityByteIndicator)
	{
		for (cnt = 0, i = 0; i < 4; i++, cnt++)
		{
			BlockStatus[cnt] = read_byte();
			pbuf[cnt] = BlockStatus[cnt];
		}
	}
	else
	{
		for (cnt = 0, i = BlockNum; i < 4; i++, cnt++)
		{
			BlockStatus[cnt] = read_byte();
			pbuf[cnt] = BlockStatus[cnt];
		}
	}
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001)
		return -1;
	ow_reset();

	return 0;
}


/*
// Input parameter: 
   1.unsigned char Segment : 0 ~ 7
   2.unsigned char Page:     0, 1;
   3.unsigned char *Buffer: Data Buffer writing to DS28E15 EEPROM
// Returns: 0 = success
        55h = The command failed because master authentication is required.
        33h = The command failed because the memory block is write protected.
        53h = The command failed because the memory block is write protected and requires master authentication.
        FFh = Error
*/
static unsigned char WriteMemory(unsigned char Segment, unsigned char Page, unsigned char *Buffer)
{

	unsigned char pbuf[20], cnt = 0, i, outcome;
	if ((ow_reset()) != 0)
		return  -1;
	write_byte(0xCC); 
	pbuf[cnt++] = WRITE_MEMORY_FUNCTION;	
	pbuf[cnt++] = ((Segment << 5) | Page) & (0xE1); 
	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) //not 0 because that the calculating result is CRC16 and the reading result is inverted CRC16
		return -1;

	cnt = 0;
	for (cnt = 0; cnt < 4; cnt++)
	{
		pbuf[cnt] = Buffer[cnt];
		write_byte(Buffer[cnt]);
	}
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();

	CRC16 = 0;
	for (i = 0; i < cnt; i++)
		docrc16(pbuf[i]);

	if (CRC16 != 0xB001) 
		return  -1;

	write_byte(0xAA);
	Delay_us(10000);
	outcome = read_byte();
	ow_reset();

	return (0xaa == outcome) ? 0 : outcome;
}

/*
Input parameter: 
   1.unsigned char Segment : 0 ~ 7
   2.unsigned char Page:     0, 1;
   3.unsigned char *Buffer: Data Buffer writing to DS28E15 EEPROM
Returns: 
	0  = success
    -1 = Error
*/
static int ReadMemory(unsigned char Segment, unsigned char Page, unsigned char *Receive)
{
	unsigned char pbuf[40], cnt = 0, i;
	if ((ow_reset()) != 0)
		return -1;
	write_byte(0xCC); 
	/* construct a packet to send */
	pbuf[cnt++] = READ_MEMORY_FUNCTION;
	pbuf[cnt++] = ((Segment << 5) | Page) & (0xE1);

	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();

	CRC16 = 0;
	for (i = 0; i < cnt; i++)
		docrc16(pbuf[i]);

	if (CRC16 != 0xB001) 
		return -1;

	for (cnt = 0, i = Segment * 4; i < 32; i++, cnt++)
	{
		Receive[cnt] = read_byte();
		pbuf[cnt] = Receive[cnt];
	}
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	CRC16 = 0;
	for (i = 0; i < cnt; i++)
		docrc16(pbuf[i]);

	ow_reset();
	if (CRC16 != 0xB001)
		return -1;

	return 0;
}

// Returns:   0 = success
//            -1 = CRC Error
//            -2 = Authentication Mac No Match 
static int WriteBlockProtection(unsigned char Block, unsigned char ProtectOption)
{
	unsigned char pbuf[20], cnt = 0, i, outcome;
	if ((ow_reset()) != 0)
		return -1;
	write_byte(0xCC); 
	pbuf[cnt++] = WRITE_BLOCK_PROTECTION; 
	pbuf[cnt++] = ProtectOption | Block; 
	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();

	CRC16 = 0;
	for (i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) 
		return -1;

	write_byte(0xAA);
	Delay_us(10000);
	outcome = read_byte();
	ow_reset();

	if(outcome != 0xaa)
		return -2;
		
	return 0;
}

/* Setting certain protection mode to Block which is already in authentication protection .
The Authenticated Write Block Protection command is used to modify the protection of a user memory block that is
already authentication protected.
// Input parameter: 
   1.unsigned char Block : specify Block number for EEPROM protection 
   		. DS28E15 include 4 Block, every block include 16Bytes.EEPROM protection apply to specified Block.
   2.unsigned char ProtectOption:  Blcok protection modes include :
   		1. Read Protection; 2.Write Protection; 3.EPROM Emulation Mode (EM);4.Authentication Protection;                
// Returns: AAh = success
            FFh = CRC Error
            55h = Authentication Mac No Match 
*/
static unsigned char AuthenticatedWriteBlockProtection(unsigned char Block, unsigned char ProtectOption)

{

	unsigned char pbuf[40], cnt = 0, i, outcome, Mac_value[32], status[4];
	unsigned char blockindex = Block;

	ReadBlockStatus(blockindex, (bool)0, status);
	memcpy(&MAC_Computer_Datainput[32], RomID_Buffer, 32);
	memcpy(&MAC_Computer_Datainput[40], &Personality_Value[2], 2);
	MAC_Computer_Datainput[42] = Block & 0x03;

	for (i = 0; i < 4; i++)
	{

		MAC_Computer_Datainput[44 + i] = ((*status >> (4 + i)) & 0x01) == 0x01 ? 0x01 : 0x00;
	}
	for (i = 0; i < 4; i++)
	{

		MAC_Computer_Datainput[48 + i] = ((ProtectOption >> (4 + i)) & 0x01) == 0x01 ? 0x01 : 0x00;
	}

	ComputeMAC256(MAC_Computer_Datainput, 55, Mac_value);

	if ((ow_reset()) != 0)
		return 0;
	write_byte(0xCC); //Skip ROM command

	/* construct a packet to send */
	pbuf[cnt++] = AUTHENTICATED_WRITEBLOCK_PROTECTION; // write WRITE_MEMORY_FUNCTION command
	pbuf[cnt++] = ProtectOption | Block;					 // Segment and Page ,Assure Bit4~Bit1:0000

	/* Send Data */
	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	/* Receive CRC */
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();

	/* calculate the CRC over this part */
	CRC16 = 0;
	for (i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) //not 0 because that the calculating result is CRC16 and the reading result is inverted CRC16
		return 0xFF;

	Delay_us(3000); //Wait for 1 times for SHA-256 Calculation;

	for (i = 0, cnt = 0; i < 32; i++, cnt++)
	{
		write_byte(Mac_value[i]);
		pbuf[cnt] = Mac_value[i];
	}
	/* Receive CRC */
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();

	/* calculate the CRC over this part */
	CRC16 = 0;
	for (i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) //not 0 because that the calculating result is CRC16 and the reading result is inverted CRC16
		return 0xFF;

	outcome = read_byte();
	if (outcome != 0xAA)
		return outcome;

	/* Send Release Byte */
	write_byte(0xAA);
	for (i = 0; i < 10; i++) //Waiting for 100ms for Secreting Loading
		Delay_us(10000);

	outcome = read_byte();
	ow_reset();
	return outcome;
}


/*
Input parameter: 
   1. bool ReadMode : 1: read, 0: write
   2. unsigned char *Buffer : Data buffer[32bytes]
Returns: 0 = success
    	-1 = Error
*/
static int ReadWriteScratchpad(bool ReadMode, unsigned char *Buffer)
{
	int ret = 0;
	unsigned char pbuf[40], cnt = 0, i;
	if ((ow_reset()) != 0)
		return -1;
	write_byte(0xCC); 
	pbuf[cnt++] = READ_WRITE_SCRATCHPAD_COMMAND; 
	pbuf[cnt++] = ReadMode ? 0x0F : 0x00;
	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001)
	{
		dbg_error("CRC16(0x%04x) != 0xB001\n", CRC16);
		return -1;
	}	
	if (ReadMode)
	{
		for (i = 0, cnt = 0; i < 32; cnt++, i++)
		{
			Buffer[cnt] = read_byte();
			pbuf[i] = Buffer[cnt];
		}
	}
	else
	{
		for (i = 0, cnt = 0; i < 32; cnt++, i++)
		{
			write_byte(Buffer[i]);
			pbuf[cnt] = Buffer[i];
		}
	}
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	ow_reset();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) 
	{
		dbg_error("CRC16(0x%04x) != 0xB001\n", CRC16);
		ret = -1;
	}	
	return ret;
}

/*
The Load and Lock Secret command
// Input parameter: 
   1. bool SecretLock_Enable : 1=Lock secret
// Returns:  0 = success
            -1 = Error
            -2 = The command failed because the secret was already locked.
*/
static int Load_and_LockSecret(bool SecretLock_Enable)
{
	unsigned char pbuf[40], cnt = 0, i, outcome;

	if ((ow_reset()) != 0)
		return -1;
	write_byte(0xCC); 
	pbuf[cnt++] = LOAD_AND_LOCKSECRET_COMMAND; 
	pbuf[cnt++] = SecretLock_Enable ? 0xE0 : 0x00;
	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();

	
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) 
		return -1;

	write_byte(0xAA);
	for (i = 0; i < 10; i++) //Waiting for 100ms for Secreting Loading
		Delay_us(10000);

	outcome = read_byte();
	ow_reset();

	return (outcome == 0xaa) ? 0 : -2;
}

/*
The Seting and Lock Secret command is used to install specified secret in application .
// Input parameter: 
   1.unsigned char *secret : Secret buffer[32bytes] 
   2.bool LockEnable : 1 = locked；
// Returns: 
	0 = success
    -1 = Error
    -2 = The command failed because the secret was already locked.
*/
static int SettingAndLock_Secret(unsigned char *secret, bool LockEnable)
{
	int BoolValue = LockEnable;
	if (ReadWriteScratchpad((bool)0, secret) != 0)
	{
		dbg_error("ReadWriteScratchpad() < 0\n");
		return -1;
	}

	return  Load_and_LockSecret(BoolValue);
}

/*
// Input parameter: 
   1.unsigned char PageNum :  0 = page0, 1 = page1.
   2.bool LockEnable:        1  = locked
// Returns: 0 = success
            -1 = Error
            -2 = The command failed because the secret was already locked.
*/
static int ComputeAndLock_Secret(unsigned char PageNum, bool LockEnable)

{
	unsigned char pbuf[40], cnt = 0, i, outcome;
	if ((ow_reset()) != 0)
		return -1;

	write_byte(0xCC);
	pbuf[cnt++] = COMPUTE_AND_LOCK_SECRET_COMMAND; 
	pbuf[cnt++] = LockEnable ? (PageNum | 0xE0) : (PageNum);
	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001)
		return -1;

	write_byte(0xAA);
	Delay_us(6000);			 //Wait for 2 times for SHA-256 Calculation;
	for (i = 0; i < 10; i++) //Waiting for 100ms for Secreting Loading
		Delay_us(10000);

	outcome = read_byte();
	ow_reset();
	return (outcome == 0xaa) ?  0 : -2;
}

/*
Input parameter: 
   1.bool Anonymous_Mode: 1 = replacing the ROM ID with FFh Bytes when MAC computation
   2.unsigned char PageNum: 0 = page0, 1 = page1
   3.unsigned char *MAC_Value: receiving data buffer for 32 Bytes Computation MAC values
Returns: 
	0 = success
    -1 = Error
*/
static int ComputeAndReadPageMAC(bool Anonymous_Mode, unsigned char PageNum, 
							/*OUT*/ unsigned char *MAC_Value)
{
	unsigned char pbuf[40], cnt = 0, i, outcome;

	if ((ow_reset()) != 0)
		return -1;

	write_byte(0xCC);
	pbuf[cnt++] = COMPUTE_AND_READ_PAGEMAC_COMMAND;
	pbuf[cnt++] = Anonymous_Mode ? (PageNum | 0xE0) : (PageNum);
	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001)
	{ 
		dbg_error( "CRC16(0x04x) != 0xB001\n", CRC16);
		return -1;
	}

	Delay_us(6000); //Wait for 2 times for SHA-256 Calculation;
	outcome = read_byte();
	if (0xaa != outcome)
		return -1;
	for (cnt = 0; cnt < 32; cnt++)
	{
		MAC_Value[cnt] = read_byte();
		pbuf[cnt] = MAC_Value[cnt];
	}
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001)
	{ 
		dbg_error( "CRC16(0x04x) != 0xB001\n", CRC16);
		return -1;
	}

#if DEBUG_ENABLE
	for (i = 0; i < 32; i++)
	{
		if (i == 0)
			printf("ds28e15 MAC[]=");

		printf("%02x,", MAC_Value[i] );

		if (i == 31)
			printf("\n");
	}
#endif

	return 0;
}

/*
The Authenticated Write Memory command is used to program one or more contiguous 4 byte segments of a memory
block that requires master authentication. The parameter byte specifies the page and segment number where the writing
begins.
// Input parameter: 
   1.unsigned char Segment:specify the location within the selected memory page where the writing begins.
   2.unsigned char Page:specify the memory page that is to be written to. Valid memory page numbers are 0 (page 0) and 1 (page 1).
   3.unsigned char *Buffer: Data buffer ready for writing specified EEPROM
   4.unsigned char *MAC: MAC value that is computed from the xpected secret, the DS28E15��s ROM ID, the number of the selected segment, 
                the number of the selected memory page,the manufacturer ID, the currently valid segment data and the new segment data;
// Returns: 0 = success
        FFh = Error
        55h = The command failed because the MAC provided is not valid.
        33h = The command failed because the block is write protected.
*/
static unsigned char AuthenticatedWriteMemory(unsigned char Segment, unsigned char Page, unsigned char *Buffer, unsigned char *MAC)
{

	unsigned char pbuf[20], cnt = 0, i, outcome;
	if ((ow_reset()) != 0)
		return -1;
	write_byte(0xCC); //Skip ROM command
	pbuf[cnt++] = AUTHENTICATED_WRITEMEMORY_COMMAND; // Read Memory Block Status or PersonalityByteindicator
	pbuf[cnt++] = ((Segment << 5) | Page) & 0xE1;
	for (i = 0; i < cnt; i++)
		write_byte(pbuf[i]);

	/* Receive CRC */
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) //not 0 because that the calculating result is CRC16 and the reading result is inverted CRC16
		return -1;

	for (i = 0, cnt = 0; i < 4; i++, cnt++)
	{
		write_byte(Buffer[i]);
		pbuf[cnt] = Buffer[i];
	}

	/* Receive CRC */
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) //not 0 because that the calculating result is CRC16 and the reading result is inverted CRC16
		return  -1;

	Delay_us(3000); //Wait for 1 times for SHA-256 Calculation;
	for (cnt = 0; i < 32;  cnt++)
	{
		write_byte(MAC[cnt]);
		pbuf[cnt] = MAC[cnt];
	}
	/* Receive CRC */
	pbuf[cnt++] = read_byte();
	pbuf[cnt++] = read_byte();
	for (CRC16 = 0,i = 0; i < cnt; i++)
		docrc16(pbuf[i]);
	if (CRC16 != 0xB001) //not 0 because that the calculating result is CRC16 and the reading result is inverted CRC16
		return -1;

	outcome = read_byte();
	if (outcome != 0xAA)
		return outcome;

	/* Send Release Byte */
	write_byte(0xAA);
	Delay_us(10000);
	outcome = read_byte();
	ow_reset();
	return 0;
}

/* 
// Input parameter: 
   1.unsigned char Segment:specify the location within the selected memory page where the writing begins.
   2.unsigned char Page:specify the memory page that is to be written to. Valid memory page numbers are 0 (page 0) and 1 (page 1).
   3.unsigned char *Bufferdata: Data buffer ready for writing specified EEPROM
// Returns: 0 = success
            FFh = CRC Error
            55h = The command failed because the MAC provided is not valid.
            33h = The command failed because the block is write protected.
*/
static unsigned char AuthenticatedWriteNewData(unsigned char Segment, unsigned char Page, unsigned char *Bufferdata)

{
	unsigned char buffer[32], Mac_value[32], newdata[4];
	unsigned char segmentindex = Segment;
	unsigned char pageindex = Page;

	memcpy(newdata, Bufferdata, 4);
	ReadMemory(Segment, Page, buffer);
	memcpy(&MAC_Computer_Datainput[32], RomID_Buffer, 32);
	memcpy(&MAC_Computer_Datainput[40], &Personality_Value[2], 2);
	MAC_Computer_Datainput[42] = Page & 0x01;
	memcpy(&(MAC_Computer_Datainput[44]), buffer, 4);
	memcpy(&MAC_Computer_Datainput[48], newdata, 4);
	ComputeMAC256(MAC_Computer_Datainput, 55, Mac_value);
	return (AuthenticatedWriteMemory(segmentindex, segmentindex, newdata, Mac_value));
}

//----------------------------------------------------------------------
/* 
Seting secret buffer for SHA-256 Algrorithm
// Input parameter: 
   1.unsigned char *secret : Data buffer for secret seting;
// Returns: None;
*/
static void set_secret(unsigned char *secret)
{
	unsigned char i;

	for (i = 0; i < 32; i++)
		SECRET[i] = secret[i];
}

//----------------------------------------------------------------------
/*  Computes SHA-256 given the MT digest buffer after first iserting
    the secret at the correct location in the array defined by all Maxim
    devices. Since part of the input is secret it is called a Message
    Autnentication Code (MAC).
//  Input Parameter: 
    1.unsigned char *MT :buffer containing the message digest
    2.short length:Length of block to digest
    3.unsigned char *MAC:result MAC in byte order used by 1-Wire device
// Returns: None;    
*/
static void ComputeMAC256(unsigned char *MT, short length, unsigned char *MAC)
{
	unsigned char i, j;
	unsigned char tmp[4];

	// check for two block format
	if (length == 119)
	{
		// insert secret
		memcpy(&MT[64], &Secret_256bit[0], 32);
		if (reverse_endian)
		{
			for (i = 0; i < 108; i += 4)
			{
				for (j = 0; j < 4; j++)
					tmp[3 - j] = MT[i + j];

				for (j = 0; j < 4; j++)
					MT[i + j] = tmp[j];
			}
		}
		ComputeSHA256(MT, 119, TRUE, TRUE, MAC);
	}
	else
	{
		memcpy(&MT[0], &Secret_256bit[0], 32);
		if (reverse_endian)
		{
			for (i = 0; i < 56; i += 4)
			{
				for (j = 0; j < 4; j++)
					tmp[3 - j] = MT[i + j];

				for (j = 0; j < 4; j++)
					MT[i + j] = tmp[j];
			}
		}
		ComputeSHA256(MT, 55, TRUE, TRUE, MAC);
	}
}

/*
//  Input Parameter: 
    1.unsigned char * MT: buffer containing the message digest 
    2.short length:Length of block to digest
    3.unsigned char* compare_MAC : MAC in byte order used by 1-Wire device to compare
                    with calculate MAC.  
// Returns: None; 
	 0  = Success
	 -1 = Error
*/
static int VerifyMAC256(unsigned char *MT, short length, unsigned char *compare_MAC)
{
	unsigned char calc_mac[32];

	ComputeMAC256(MT, length, calc_mac);
#if DEBUG_ENABLE
	for (int i = 0; i < 32; i++)
	{
		if (i == 0)
			printf("Host    MAC[]=");
		printf("%02x,", calc_mac[i] );
		if (i == 31)
			printf("\n");
	}
#endif

	for (int i = 0; i < 32; i++)
	{
		if (compare_MAC[i] != calc_mac[i])
			return -1;
	}
	return 0;
}

static void CalculateNextSecret256(unsigned char *binding, unsigned char *partial, int page_num, unsigned char *manid)
{
	unsigned char MT[128];
	unsigned char MAC[64];

	memset(MT, 0, 128);
	memcpy(&MT[0], binding, 32);
	memcpy(&MT[32], partial, 32);
	memcpy(&MT[96], RomID_Buffer, 8);

	MT[106] = page_num;
	MT[105] = manid[0];
	MT[104] = manid[1];

	ComputeMAC256(MT, 119, MAC);
	set_secret(MAC);
}

static ulong sha_ch(unsigned long x, ulong y, ulong z)
{
	return (x & y) ^ ((~x) & z);
}

static ulong sha_maj(ulong x, ulong y, ulong z)
{
	ulong temp = x & y;
	temp ^= (x & z);
	temp ^= (y & z);
	return temp; //(x & y) ^ (x & z) ^ (y & z);
}

static ulong sha_rotr_32(ulong val, ushort r)
{
	val = val & 0xFFFFFFFFL;
	return ((val >> r) | (val << (32 - r))) & 0xFFFFFFFFL;
}

static ulong sha_shr_32(ulong val, ushort r)
{
	val = val & 0xFFFFFFFFL;
	return val >> r;
}

static ulong sha_bigsigma256_0(ulong x)
{
	return sha_rotr_32(x, 2) ^ sha_rotr_32(x, 13) ^ sha_rotr_32(x, 22);
}

static ulong sha_bigsigma256_1(ulong x)
{
	return sha_rotr_32(x, 6) ^ sha_rotr_32(x, 11) ^ sha_rotr_32(x, 25);
}

static ulong sha_littlesigma256_0(ulong x)
{
	return sha_rotr_32(x, 7) ^ sha_rotr_32(x, 18) ^ sha_shr_32(x, 3);
}

static ulong sha_littlesigma256_1(ulong x)
{
	return sha_rotr_32(x, 17) ^ sha_rotr_32(x, 19) ^ sha_shr_32(x, 10);
}

static void sha_copy32(ulong *p1, ulong *p2, ushort length)
{
	while (length > 0)
	{
		*p2++ = *p1++;
		length--;
	}
}

static void sha_copyWordsToBytes32(ulong *input, unsigned char *output, ushort numwords)
{
	unsigned long temp;
	unsigned short i;

	for (i = 0; i < numwords; i++)
	{
		temp = *input++;
		*output++ = (uchar)(temp >> 24);
		*output++ = (uchar)(temp >> 16);
		*output++ = (uchar)(temp >> 8);
		*output++ = (uchar)(temp);
	}
}

static void sha_writeResult(ushort reverse, uchar *outpointer)
{
	unsigned char i, tmp;
	
	sha_copyWordsToBytes32(H32, outpointer, 8);
	if (reverse)
	{
		for (i = 0; i < 16; i++)
		{
			tmp = outpointer[i];
			outpointer[i] = outpointer[31 - i];
			outpointer[31 - i] = tmp;
		}
	}
}

static unsigned long sha_getW(int index)
{
	unsigned long newW;
	if (index < 16)
	{
		return W32[index];
	}

	newW = sha_littlesigma256_1(W32[(index - 2) & 0x0f]) +
		   W32[(index - 7) & 0x0f] +
		   sha_littlesigma256_0(W32[(index - 15) & 0x0f]) +
		   W32[(index - 16) & 0x0f];
	W32[index & 0x0f] = newW & 0xFFFFFFFFL; // just in case...

	return newW;
}

static void sha_prepareSchedule(unsigned char *message)
{
	// we need to copy the initial message into the 16 W registers
	unsigned char i, j;
	unsigned long temp;
	for (i = 0; i < 16; i++)
	{
		temp = 0;
		for (j = 0; j < 4; j++)
		{
			temp = temp << 8;
			temp = temp | (*message & 0xff);
			message++;
		}

		W32[i] = temp;
	}
}

//----------------------------------------------------------------------
// Hash a single block of data.
//
static void sha256_hashblock(unsigned char *message, ushort lastblock)
{
	ushort sha1counter = 0;
	ushort sha1functionselect = 0;
	ushort i;
	unsigned long nodeT1, nodeT2;

	unsigned long Wt, Kt;

	// chunk the original message into the working schedule
	sha_prepareSchedule(message);

	a32 = H32[0];
	b32 = H32[1];
	c32 = H32[2];
	d32 = H32[3];
	e32 = H32[4];
	f32 = H32[5];
	g32 = H32[6];
	h32 = H32[7];

	// rounds
	for (i = 0; i < 64; i++)
	{
		Wt = sha_getW(i);
		Kt = SHA_CONSTANTS[i];

		nodeT1 = (h32 + sha_bigsigma256_1(e32) + sha_ch(e32, f32, g32) + Kt + Wt); // & 0xFFFFFFFFL;
		nodeT2 = (sha_bigsigma256_0(a32) + sha_maj(a32, b32, c32));				   // & 0xFFFFFFFFL;
		h32 = g32;
		g32 = f32;
		f32 = e32;
		e32 = d32 + nodeT1;
		d32 = c32;
		c32 = b32;
		b32 = a32;
		a32 = nodeT1 + nodeT2;

		sha1counter++;
		if (sha1counter == 20)
		{
			sha1functionselect++;
			sha1counter = 0;
		}
	}

	if (!lastblock)
	{
		// now fix up our H array
		H32[0] += a32;
		H32[1] += b32;
		H32[2] += c32;
		H32[3] += d32;
		H32[4] += e32;
		H32[5] += f32;
		H32[6] += g32;
		H32[7] += h32;
	}
	else
	{
		// now fix up our H array
		H32[0] = a32;
		H32[1] = b32;
		H32[2] = c32;
		H32[3] = d32;
		H32[4] = e32;
		H32[5] = f32;
		H32[6] = g32;
		H32[7] = h32;
	}
}

//----------------------------------------------------------------------
// Computes SHA-256 given the data block 'message' with no padding.
// The result is returned in 'digest'.
//
// 'message'  - buffer containing the message
// 'skipconst' - skip adding constant on last block (skipconst=1)
// 'reverse' - reverse order of digest (reverse=1, MSWord first, LSByte first)
// 'digest'   - result hash digest in byte order used by 1-Wire device
//
static void ComputeSHA256(unsigned char *message, short length, ushort skipconst, ushort reverse, 
					unsigned char *digest)
{
	ushort bytes_per_block;
	ushort nonpaddedlength;
	ushort numblocks;
	ushort i, j;
	ulong bitlength;
	ushort markerwritten;
	ushort lastblock;
	ushort wordsize = 32;
	unsigned char workbuffer[256]; 

	// if wordsize is 32 bits, we need 512 bit blocks.  else 1024 bit blocks.
	// that means 16 words are in one message.
	bytes_per_block = 16 * (wordsize / 8);
	// 1 byte for the '80' that follows the message, 8 or 16 bytes of length
	nonpaddedlength = length + 1 + (wordsize / 4);
	numblocks = nonpaddedlength / bytes_per_block;
	if ((nonpaddedlength % bytes_per_block) != 0)
	{
		numblocks++;
	}

	sha_copy32(SHA_256_Initial, H32, SHA_256_INITIAL_LENGTH);

	bitlength = 8 * length;
	markerwritten = 0;
	// 'length' is our number of bytes remaining.
	for (i = 0; i < numblocks; i++)
	{
		if (length > bytes_per_block)
		{
			memcpy(workbuffer, message, bytes_per_block);
			length -= bytes_per_block;
		}
		else if (length == bytes_per_block)
		{
			memcpy(workbuffer, message, length);
			length = 0;
		}
		else // length is less than number of bytes in a block
		{
			memcpy(workbuffer, message, length);
			// message is now used for temporary space
			message = workbuffer + length;
			if (markerwritten == 0)
			{
				*message++ = 0x80;
				length++;
			}

			while (length < bytes_per_block)
			{
				// this loop is inserting padding, in this case all zeroes
				*message++ = 0;
				length++;
			}
			length = 0;
			// signify that we have already written the 80h
			markerwritten = 1;
		}

		// on the last block, put the bit length at the very end
		lastblock = (i == (numblocks - 1));
		if (lastblock)
		{
			// point at the last byte in the block
			message = workbuffer + bytes_per_block - 1;
			for (j = 0; j < wordsize / 4; j++)
			{
				*message-- = (uchar)bitlength;
				bitlength = bitlength >> 8;
			}
		}

		// SHA in software
		sha256_hashblock(workbuffer, (ushort)(lastblock && skipconst));
		message += bytes_per_block;
	}

	sha_writeResult(reverse, digest);
}

/*******************************************************************************/
static void Computer_UniqueSecret(unsigned char *pagedata, 
							unsigned char pagenum, 
							unsigned char *scratchpaddata, 
							unsigned char *basicsecret)
{
	unsigned char unique_secret[32];

	/*test how to load 256bit basic secret */
	SettingAndLock_Secret(basicsecret, (bool)0);
	memcpy(Secret_256bit, basicsecret, 32);

	/* write EEPROM   Segment0-7;  */
	if (ReadMemory(SEGMENT0, PAGE0, EEPROM) == 0xaa)
	{
		for (int i = 0; i < 8; i++)
			WriteMemory(i, PAGE0, pagedata + 4 * i);
	}

	/*Wite  Scratchpad buffer */
	ReadWriteScratchpad((bool)0, scratchpaddata);

	/* DS28E15 computer unique secret and unlock key */
	ComputeAndLock_Secret(pagenum, 0);

	/*Host computer unique secret by eeprom,romid, scratchpad*/
	if (ReadMemory(SEGMENT0, PAGE0, MAC_Computer_Datainput) == 0xaa)
	{
		memcpy(&MAC_Computer_Datainput[32], scratchpaddata, 32);
		memcpy(&MAC_Computer_Datainput[96], RomID_Buffer, 8);
		memcpy(&MAC_Computer_Datainput[104], &Personality_Value[2], 2);
		MAC_Computer_Datainput[106] = 0x00;
	}
	ComputeMAC256(MAC_Computer_Datainput, 119, unique_secret);
}



/**************************************************************************************************
* 全局函数声明、定义
***************************************************************************************************/
// 初始化端口
// retrun: 0 = successful,  -1 = error
API int	ds28e15_init(void)
{
	int ret;
	ret = dev_handler_open();
	if (ret < 0)
	{
		dbg_error("dev_register_open() < 0\n");
		return -1;
	}

	init_port();
	return 0;
}


// 校验密码(必须与写到ds28e15中的密码相同，最大32bytes)
// retrun: 0 = successful,  -1 = error
API int ds28e15_verify_secret(char secret[32])
{
	int ret = 0;
	size_t len = 0;

	memset(Secret_256bit, 0, sizeof(Secret_256bit));
	len = strlen(secret);
	len = (len < 32) ? len : 32;
	memcpy(Secret_256bit, secret, len);

	//-- 读取ROM ID
	memset(RomID_Buffer, 0, sizeof(RomID_Buffer));
	for (size_t i = 0; i < 3; i++)
	{	
 		ret = Read_RomID(RomID_Buffer);
		if (0 == ret) break;
	}
	if (ret < 0)
	{
		dbg_error("Read_RomID()<0 \n");
		return -1;
	}
	dbg_printf("RomID[]= %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x \n\n",
		RomID_Buffer[0],RomID_Buffer[1],RomID_Buffer[2],RomID_Buffer[3],
		RomID_Buffer[4],RomID_Buffer[5],RomID_Buffer[6],RomID_Buffer[7]);

    //--读取 Manufacturer id,
	for (size_t i = 0; i < 3; i++)
	{
   		ret = ReadBlockStatus(0, 1, Personality_Value);
		if (0 == ret) break;
	}
   if (ret < 0)
   {
	   dbg_error("ReadBlockStatus() < 0 \n");
	   return -1;
   }
	dbg_printf("Manufacturer_ID[]= %02x,%02x,%02x,%02x \n\n", 
		Personality_Value[0], Personality_Value[1], Personality_Value[2], Personality_Value[3]);

	//-- 设置随机数
	for (size_t i = 0; i < 3; i++)
	{
		ret = ReadWriteScratchpad(WRITE, Scratch_Writebuffer);
		if (0 == ret) break;
	}
	if (ret < 0)
	{
		dbg_error("ReadWriteScratchpad() < 0\n");
		return -1;
	}
	//-- 计算并读出MAC
	for (size_t i = 0; i < 3; i++)
	{
		ret  = ComputeAndReadPageMAC(0, PAGE0, MAC_Read_Value);
		if (0 == ret) break;
	}
	if (ret < 0)
	{
		dbg_error("ComputeAndReadPageMAC() < 0 \n");
		return -1;
	}

	for (size_t i = 0; i < 3; i++)
	{
		ret = ReadMemory(0, 0, MAC_Computer_Datainput);
		if (0 == ret) break;
	}
	if ( ret < 0)
	{
		dbg_error("ReadMemory() < 0 \n");
		return -1;
	}
	for (size_t i = 0; i < 3; i++)
	{
		ret = ReadWriteScratchpad(WRITE, Scratch_Writebuffer);
		if (0 == ret) break;
	}
	if (ret < 0)
	{
		dbg_error("ReadWriteScratchpad() < 0 \n");
		return -1;
	}
	memcpy(&MAC_Computer_Datainput[32], Scratch_Writebuffer, 32);
	memcpy(&MAC_Computer_Datainput[96], RomID_Buffer, 8);
	memcpy(&MAC_Computer_Datainput[104], &Personality_Value[2], 2);
	MAC_Computer_Datainput[106] = 0x00; // 0x00=page0; page1=0x01;
	for (size_t i = 0; i < 3; i++)
	{
		ret = VerifyMAC256(MAC_Computer_Datainput, 119, MAC_Read_Value);
		if (0 == ret) break;
	}
	if (ret < 0)
	{
		dbg_error("VerifyMAC256() < 0 \n");
		return -1;
	}

	return 0;
}

// 写ds28e15的密码
// retrun: 0 = successful,  -1 = error
API int ds28e15_write_secret(char secret[32])
{
	int ret;
	size_t len = strlen(secret);
	len = (len < 32) ? len : 32;
	memset(Secret_256bit, 0, sizeof(Secret_256bit));
	memcpy(Secret_256bit, secret, len);
	for (size_t i = 0; i < 3; i++)
	{	// 连续操作多次
		ret = SettingAndLock_Secret(Secret_256bit, 0);
		if (ret == 0) 
			return 0;
	}

	dbg_error("SettingAndLock_Secret() < 0\n");
	return -1;
}


#if 1
//---------------------------------------------------------------------------------------
// 生产时，使用该程序将密码写入加密芯片ds28e15
//---------------------------------------------------------------------------------------
static void usage(char file_name[])
{
	printf("usage :\n");
	printf(" %s    <secret> \n\n", file_name);
}

int main(int argc, char *argv[])
{
	int ret;

	if (argc != 2)
	{
		usage(argv[0]);
		return -1;
	}

	ds28e15_init();      					 // 初始化
	ret = ds28e15_write_secret( argv[1] );   // 写入密码
	if (ret < 0)
		printf(" -- ds28e15 write Error -- \n");
	else
		printf(" -- ds28e15 write Ok -- \n");

	return 0;
}
#endif


#if 0
//---------------------------------------------------------------------------------------
// 测试代码，校验密码
//---------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
	int ret = 0;

	ds28e15_init();    // 初始化

	for (size_t i = 0; i < 3; i++)
	{
		ret = ds28e15_verify_secret("password:ds28e15");   // 校验密码（连续3次）
		if (0 == ret)  break;
		
	}
	if (0 == ret)
		printf("-- Verify OK --\n\n");
	else
		printf ("-- Verify Error --\n\n");

}
#endif

